package com.wbc.utils;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 基于 jdk8 原生实现反射工具,方便反射的操作
 * @author wangbingchen
 * @Description
 * @create 2022-01-15 9:00
 *
 * 反射工具 可以执行任何类的任何方法
 */
public class ReflectionUtil {

    public static void main(String[] args) {
        ReflectionUtil test = new ReflectionUtil(".TestUtil");
        Object tt = test.runMethod("initMaxDou");
        System.out.println(tt);
    }


    //1允许执行私有方法 2允许执行跨包访问 3 正常
    private static int permissions = 1;

    //配置包路径
    private static String classPackagePath = "com.wbc";

    //类对象
    private Class<?> aClass = null;

    //实例化对象
    private Object object = null;

    //最近一次调用方法的返回结果
    private Object returnObj = null;

    private ReflectionUtil(){
    }

    /**
     *
     * @param className 使用方式: 1.传入类名全路径
     *                  2.配置 classPackagePath = "com.wbc";为你自己的包 此包下的类传入方式
     *                  .类名
     */

    public ReflectionUtil(String className, Object... args){
        myLoadClass(className);
        newInstance(args);

    }


    /**
     * 加载类信息
     * @param className
     */
    private void myLoadClass(String className) {
        if(!className.contains(".")){
            className = classPackagePath+"."+className;
        }
        if(className.indexOf(".")==0){
            className = ReflectionUtil.class.getPackage().getName()+className;
        }

        try {
            this.aClass = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    /**
     *
     * @param methodName 方法名称
     * @param args 方法参数
     * @return 执行结果
     */
    public Object runMethod(String methodName, Object... args) {

        int length = 0;
        if(args != null){
            length = args.length;
        }
        if (object == null){
            throw new RuntimeException("未实例化对象");
        }
        //参数长度和 方法名称
        Method[] declaredMethods = aClass.getDeclaredMethods();
        //拿到所有的方法
        for (Method method : declaredMethods) {
            if(methodName.equals(method.getName())&&method.getParameterCount()==length){
                Class<?>[] parameterTypes = method.getParameterTypes();
                boolean boo = true;
                for (int i = 0; i < length; i++) {
                    if(!args[i].getClass().equals(parameterTypes[i])){
                        boo = false;
                        break;
                    }
                }
                if (boo){
                    //执行方法
                    try {
                        //判断权限
                        if((Modifier.isProtected(method.getModifiers()) && permissions != 3)
                                ||(permissions == 1 && Modifier.isPrivate(method.getModifiers()))){
                            method.setAccessible(true);
                        }

                        returnObj = method.invoke(object, args);
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }

                }


            }

        }
        return returnObj;
    }

    /**
     * 调用构造
     * @param args 构造参数
     */
    private void newInstance(Object... args) {
        int length = 0;
        if(args != null){
            length = args.length;
        }
        if(aClass == null){
            System.out.println("未加载类");
            return;
        }

        Constructor<?>[] constructors = aClass.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            if(constructor.getParameterCount()==length){
                Class<?>[] parameterTypes = constructor.getParameterTypes();
                boolean boo = true;
                for (int i = 0; i < length; i++) {
                    if(!args[i].getClass().equals(parameterTypes[i])){
                        boo = false;
                        break;
                    }
                }
                if (boo){
//                    System.out.println("构建对象");
                    try {
                        //判断权限
                        if(permissions != 3){
                            constructor.setAccessible(true);
                        }
                        object = constructor.newInstance(args);

                    } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
                        e.printStackTrace();
                    }

                }

            }

        }

    }


}
